<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>First steps</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Winapi, Windows API, C, no MFC">
<meta name="description" content="In this part of the Winapi tutorial, 
we will create our first programs.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>First steps</h1>


<p>
In this part of the Winapi tutorial, we will create some simple examples. 
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h2>Simple program</h2>

<p>
Here is the most simple program. It will pop up a small dialog box.
</p>

<pre class="code">
#include &lt;windows.h&gt;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    PWSTR pCmdLine, int CmdShow)
{
  MessageBoxW(NULL, L"First Program", L"First", MB_OK);

  return 0;
}
</pre>

<p>
A small dialog box is shown on the screen. It has a caption, message and 
an OK button.
</p>

<pre class="explanation">
#include &lt;windows.h&gt;
</pre>

<p>
We include the basic function declarations, constants, data types and structures. 
</p>

<pre class="explanation">
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    PWSTR pCmdLine, int CmdShow)
</pre>

<p>
The <code>wWinMain()</code> function is an entry point to our application.
</p>

<pre class="explanation">
MessageBoxW(NULL, L"First Program", L"First", MB_OK);
</pre>

<p>
The <code>MessageBoxW()</code> function displays a simple message box. The first 
parameter is the owner window. In our case, the dialog box has no owner. 
The next two parameters provide the message text and the caption. The last 
parameter defines the message dialog type. We have a dialog box with one 
OK button.
</p>

<img src="/img/gui/winapi/messagebox.png" alt="Simple message box">
<div class="figure">Simple message box</div>


<h2>Centering a window</h2>

<p>
In the next code example, we will center the window on the screen. 
</p>


<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void CenterWindow(HWND);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PWSTR pCmdLine, int nCmdShow)
{
  MSG  msg;    
  WNDCLASSW wc = {0};
  wc.lpszClassName = L"Center";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);
  
  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Center",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                100, 100, 250, 150, 0, 0, hInstance, 0);  

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam)
{
  switch(msg)  
  {
      case WM_CREATE:
      {
          CenterWindow(hwnd);
          return 0;
      }

      case WM_DESTROY:
      {
          PostQuitMessage(0);
          return 0;
      }
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void CenterWindow(HWND hwnd)
{
    RECT rc;
    
    GetWindowRect(hwnd, &rc) ;
    
    SetWindowPos(hwnd, 0, 
        (GetSystemMetrics(SM_CXSCREEN) - rc.right)/2,
        (GetSystemMetrics(SM_CYSCREEN) - rc.bottom)/2,
         0, 0, SWP_NOZORDER|SWP_NOSIZE);
}
</pre>

<p>
In order to center a window on the screen, we need to have the dimensions
of the window and of the screen. 
</p>

<pre class="explanation">
case WM_CREATE:
{
    CenterWindow(hwnd);
    return 0;
}
</pre>

<p>
We call the user defined <code>CenterWindow()</code> function during the 
<code>WM_CREATE</code> message.
</p>

<pre class="explanation">
GetWindowRect(hwnd, &amp;rc) ;
</pre>

<p>
With the <code>GetWindowRect()</code> function, we retrieve the dimensions of 
the bounding rectangle of the specified window. 
</p>

<pre class="explanation">
SetWindowPos(hwnd, 0, 
    (GetSystemMetrics(SM_CXSCREEN) - rc.right)/2,
    (GetSystemMetrics(SM_CYSCREEN) - rc.bottom)/2,
     0, 0, SWP_NOZORDER|SWP_NOSIZE);
</pre>

<p>
The <code>SetWindowPos()</code> method positions a window on the screen.
The <code>GetSystemMetrics()</code> function is used to get the width and
height of the screen.
</p>


<h2>More Windows</h2>

<p>
A window is created from a specific window class. A window class defines a set 
of behaviors that several windows might have in common.  Some classes are 
already predefined in the system. A custom window class must be registered.
After that, we can create windows of this new window class. A window is
created using by calling the <code>CreateWindowW()</code> function. Its first
parameter is the window class name.
</p>

<p>
Each window has a window procedure. It is a function that is called by the OS, 
when users interact with the window. In the following example, we create three 
windows. One parent window and two child windows. 
</p>


<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK PanelProc(HWND, UINT, WPARAM, LPARAM);

void RegisterRedPanelClass(void);
void RegisterBluePanelClass(void);


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
			              PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;    
  WNDCLASSW wc = {0};
  wc.lpszClassName = L"ColorWindows";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);
  
  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"ColorWindows",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                100, 100, 250, 180, 0, 0, hInstance, 0);  

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam)
{    
  switch(msg)  
  {
    case WM_CREATE:

      RegisterRedPanelClass();

      CreateWindowW(L"RedPanelClass", NULL, 
        WS_CHILD | WS_VISIBLE,
        20, 20, 80, 80,
        hwnd, (HMENU) 1, NULL, NULL);

      RegisterBluePanelClass();

      CreateWindowW(L"BluePanelClass", NULL, 
        WS_CHILD | WS_VISIBLE,
        120, 20, 80, 80,
        hwnd, (HMENU) 2, NULL, NULL);

    break;

    case WM_DESTROY:
    
      PostQuitMessage(0);
      return 0; 
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK PanelProc( HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam )
{
  switch(msg)  
  {
    case WM_LBUTTONUP:
    
      Beep(50, 40);
      break;    
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void RegisterRedPanelClass(void) 
{
  HBRUSH hbrush = CreateSolidBrush(RGB(255, 0, 0));

  WNDCLASSW rwc = {0};
  rwc.lpszClassName = L"RedPanelClass";
  rwc.hbrBackground = hbrush;
  rwc.lpfnWndProc   = PanelProc;
  rwc.hCursor       = LoadCursor(0, IDC_ARROW);
  RegisterClassW(&amp;rwc); 
}

void RegisterBluePanelClass(void) 
{
  HBRUSH hbrush = CreateSolidBrush(RGB(0, 0, 255));

  WNDCLASSW rwc = {0};
  rwc.lpszClassName = L"BluePanelClass";
  rwc.hbrBackground = hbrush;
  rwc.lpfnWndProc   = PanelProc;
  rwc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;rwc);
}
</pre>

<p>
We have an application window with two child windows. The two child windows 
have blue and red backgrounds. 
</p>

<pre class="explanation">
HBRUSH hbrush = CreateSolidBrush(RGB(255, 0, 0));
...
rwc.hbrBackground = hbrush;
</pre>

<p>
To create a coloured window background, we create a custom solid brush by 
calling the <code>CreateSolidBrush()</code> function. To specify a colour, we 
use the RGB macro. As we know, any color can be created by combining red,
green a blue colours. Then we set the <code>hbrBackground</code> parameter of 
the window class structure to this newly created brush. 
</p>

<pre class="explanation">
RegisterRedPanelClass();

CreateWindowW(L"RedPanelClass", NULL, 
  WS_CHILD | WS_VISIBLE,
  20, 20, 80, 80,
  hwnd, (HMENU) 1, NULL, NULL);
</pre>

<p>
First we register a new window class. After this step, we create a window of
this class.
</p>

<p>
Both of our child windows share the PanelProc window procedure. This procedure 
is called by the Windows OS when we interact with it.
</p>

<pre class="explanation">
case WM_LBUTTONUP:

  Beep(50, 40);
  break;    
</pre>

<p>
We interact with our child windows, when we click on them. By left clicking
on the child window, the Windows OS calls the child window procedure and sends a
<code>WM_LBUTTONUP</code> message. In our example, we call the 
<code>Beep()</code> function. If we left click on the background of the two 
child windows, we hear a beep sound. 
</p>

<pre class="explanation">
void RegisterRedPanelClass(void) 
{
  HBRUSH hbrush = CreateSolidBrush(RGB(255, 0, 0));

  WNDCLASSW rwc = {0};
  rwc.lpszClassName = L"RedPanelClass";
  rwc.hbrBackground = hbrush;
  rwc.lpfnWndProc   = PanelProc;
  rwc.hCursor       = LoadCursor(0, IDC_ARROW);
  RegisterClassW(&amp;rwc); 
}   
</pre>

<p>
This function registers a new window class. Windows of this window class type
have red backgrounds. Edit, Button or Static controls are created from predefined 
window classes, which are already available to all processes. So in these cases 
we do not need to register a window class for them. 
</p>

<img src="/img/gui/winapi/morewindows.png" alt="More windows">
<div class="figure">Figure: More windows</div>


<h2>The escape key</h2>

<p>
Applications are often terminated by pressing the escape key. 
A message box is also shown to confirm the termination. 
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    PWSTR pCmdLine, int CmdShow)
{
  MSG  msg;    
  WNDCLASSW wc = {0};
  wc.lpszClassName = L"Escape";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);
    
  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Escape",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                100, 100, 250, 180, 0, 0, hInstance, 0);  

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      TranslateMessage(&amp;msg);
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam )
{    
  switch(msg)  
  {
    case WM_KEYDOWN:

      if (wParam == VK_ESCAPE) {
          int ret = MessageBoxW(NULL, L"Are you sure to quit?", 
                                  L"Message", MB_OKCANCEL);
          if ( ret == IDOK) {
    	        SendMessage(hwnd, WM_CLOSE, 0, 0);
          }
      }
      break;

    case WM_DESTROY:

        PostQuitMessage(0);
      break; 
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}
</pre>

<p>
It is a common practice to ask a user if he really wants to close an application.
If we have a clock or a calculator than it does not matter that much. But if 
we have a text editor or a drawing application, it does matter. We might 
accidentally press the escape key and loose all our modifications.
</p>

<pre class="explanation">
case WM_KEYDOWN:

  if (wParam == VK_ESCAPE) {
      int ret = MessageBoxW(NULL, L"Are you sure to quit?", 
                              L"Message", MB_OKCANCEL);
      if ( ret == IDOK) {
	        SendMessage(hwnd, WM_CLOSE, 0, 0);
      }
  }
  break;
</pre>

<p>
If we press a key, the window procedure receives a <code>WM_KEYDOWN</code> 
message. The <code>wParam</code> parameter has a key code. We can close the
window by sending a <code>WM_CLOSE</code> message. 
</p>


<h2>Moving a window</h2>

<p>
When we move a window on the screen, the window procedure receives the 
<code>WM_MOVE</code> message. In our example we display the current window 
position on the screen.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void CreateLabels(HWND);

HWND hwndSta1;
HWND hwndSta2;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    PWSTR pCmdLine, int CmdShow)
{
  HWND hwnd;
  MSG  msg;

  WNDCLASSW wc = {0};
  wc.lpszClassName = L"Moving";
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);
  
  RegisterClassW(&amp;wc);
  hwnd = CreateWindowW(wc.lpszClassName, L"Moving",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                150, 150, 250, 180, 0, 0, hInstance, 0);
		
  CreateLabels(hwnd);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
  }
  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam)
{

  wchar_t buf[10];
  RECT rect;

  switch(msg)  
  {
    case WM_MOVE:
      GetWindowRect(hwnd, &amp;rect);

      _itow(rect.left, buf, 10);
      SetWindowTextW(hwndSta1, buf);

      _itow(rect.top, buf, 10);
      SetWindowTextW(hwndSta2, buf);

      break;

    case WM_DESTROY:
      PostQuitMessage(0);
      break; 
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void CreateLabels(HWND hwnd){

  CreateWindowW(L"static", L"x: ",
      WS_CHILD | WS_VISIBLE,
      10, 10, 25, 25, 
      hwnd, (HMENU) 1, NULL, NULL);

  hwndSta1 = CreateWindowW(L"static", L"150",
      WS_CHILD | WS_VISIBLE,
      40, 10, 55, 25, 
      hwnd, (HMENU) 2, NULL, NULL);

  CreateWindowW(L"static", L"y: ",
      WS_CHILD | WS_VISIBLE,
      10, 30, 25, 25, 
      hwnd, (HMENU) 3, NULL, NULL);

  hwndSta2 = CreateWindowW(L"static", L"150",
      WS_CHILD | WS_VISIBLE,
      40, 30, 55, 25, 
      hwnd, (HMENU) 4, NULL, NULL);
}
</pre>

<p>
Normally, we would create the static text controls during the 
<code>WM_CREATE</code> message. This was not possible. Because the window 
is being moved during the creation and we receive error messages. We 
wanted to access a window that did not exist yet. That's why we put the creation 
of the static text windows in a separate function, which is called immediately 
after the main window is created. 
</p>

<pre class="explanation">
void CreateLabels(HWND hwnd){

  CreateWindowW(L"static", L"x: ",
      WS_CHILD | WS_VISIBLE,
      10, 10, 25, 25, 
      hwnd, (HMENU) 1, NULL, NULL);

  hwndSta1 = CreateWindowW(L"static", L"150",
      WS_CHILD | WS_VISIBLE,
      40, 10, 55, 25, 
      hwnd, (HMENU) 2, NULL, NULL);

  CreateWindowW(L"static", L"y: ",
      WS_CHILD | WS_VISIBLE,
      10, 30, 25, 25, 
      hwnd, (HMENU) 3, NULL, NULL);

  hwndSta2 = CreateWindowW(L"static", L"150",
      WS_CHILD | WS_VISIBLE,
      40, 30, 55, 25, 
      hwnd, (HMENU) 4, NULL, NULL);
}
</pre>

<p>
There are four static text controls. Two of them change during the life of 
the application. So we need only two handles. 
</p>

<pre class="explanation">
case WM_MOVE:
  GetWindowRect(hwnd, &rect);

  _itow(rect.left, buf, 10);
  SetWindowTextW(hwndSta1, buf);

  _itow(rect.top, buf, 10);
  SetWindowTextW(hwndSta2, buf);

  break;
</pre>

<p>
To get the window coordinates, we call the <code>GetWindowRect()</code> function. 
The coordinate is a number. We must convert the number to characters. To 
accomplish this, we use the <code>_itow()</code> function call. 
</p>


<img src="/img/gui/winapi/moving.png" alt="Moving a window">
<div class="figure">Figure: Moving a window</div>


<h2>Flashing a window</h2>

<p>
Sometimes when an important event happens, the title bar or/and 
the taskbar button start to flash. The flashing is the change of the 
title bar from inactive status to active status and vice versa. This is a 
common feature in Miranda IM, when we receive a new message.
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;    
  WNDCLASSW wc = {0};
  wc.lpszClassName = L"Flash";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0,IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Flash",
               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
               100, 100, 250, 180, 0, 0, hInstance, 0);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam )
{
  FLASHWINFO fwi;

  switch(msg)  
  {
      case WM_CREATE:

          CreateWindowW(L"Button", L"Flash",
                  WS_CHILD | WS_VISIBLE,
                  10, 10, 80, 25, 
                  hwnd, (HMENU) 1, NULL, NULL);
          break;

      case WM_COMMAND:

          fwi.cbSize = sizeof(fwi);
          fwi.dwFlags = FLASHW_ALL;
          fwi.dwTimeout = 0;
          fwi.hwnd = hwnd;
          fwi.uCount = 4;

          FlashWindowEx(&amp;fwi);
          break;

      case WM_DESTROY:

          PostQuitMessage(0);
          break; 
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}
</pre>

<p>
In order to flash a window, we must do two steps. Create and fill 
a <code>FLASHWINFO</code> structure and call the <code>FlashWindowEx()</code> 
function.
</p>

<pre class="explanation">
fwi.dwFlags = FLASHW_ALL;
</pre>

<p>
We have set the <code>FLASHW_ALL</code> flag. This will flash both the title 
bar and the taskbar button. To flash only the titlebar, we use 
<code>FLASHW_CAPTION</code>. To flash the taskbar button, we can use the 
<code>FLASHW_TRAY</code> flag.
</p>

<pre class="explanation">
fwi.dwTimeout = 0;
</pre>

<p>
The <code>dwTimeout</code> member is the rate at which the window is to be 
flashed, in milliseconds. If <code>dwTimeout</code> is zero, the function uses 
he default cursor blink rate.
</p>

<pre class="explanation">
fwi.hwnd = hwnd;
fwi.uCount = 4;
</pre>

<p>
Here we set which window to flash and how many times we want to flash it. 
In our case, we will flash the main window four times.
</p>

<pre class="explanation">
FlashWindowEx(&amp;fwi);
</pre>

<p>
This function call actually starts the flashing.
</p>

<p>
In this part of the Winapi tutorial, we have created some simple examples. 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br> 

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 29, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
